////////////////////////////////////////////////////////////////////////////////
//
//  FLEX USER GROUP HOKURIKU
//  Copyright 2009 Flex User Group Hokuriku
//  All Rights Reserved.
// 
//  NOTICE: Flex User Group Hokuriku permits you to use, 
//  modify, and distribute this file 
//  in accordance with the terms of the license agreement accompanying it.
//
////////////////////////////////////////////////////////////////////////////////
package net.fxug.hokuriku.chocolat.helper
{
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.SQLErrorEvent;
    import flash.events.SQLEvent;
    
    import mx.collections.ArrayCollection;
    import mx.core.IMXMLObject;
    import mx.events.FlexEvent;
    import mx.logging.ILogger;
    
    import net.fxug.hokuriku.chocolat.dao.DatabaseManager;
    import net.fxug.hokuriku.chocolat.dao.SessionDao;
    import net.fxug.hokuriku.chocolat.errors.NetworkInterfaceError;
    import net.fxug.hokuriku.chocolat.events.SQLVoteEvent;
    import net.fxug.hokuriku.chocolat.events.SessionTimerEvent;
    import net.fxug.hokuriku.chocolat.events.ViewChangeEvent;
    import net.fxug.hokuriku.chocolat.events.VoteStatusEvent;
    import net.fxug.hokuriku.chocolat.model.ApplicationDataModel;
    import net.fxug.hokuriku.chocolat.model.SessionTimer;
    import net.fxug.hokuriku.chocolat.model.NetworkInterfaceManager;
    import net.fxug.hokuriku.chocolat.model.NetworkInterfaceData;
    import net.fxug.hokuriku.chocolat.service.IVoteWatcher;
    import net.fxug.hokuriku.chocolat.service.SocketServer;
    import net.fxug.hokuriku.chocolat.service.TwitterSearchVoteWatcher;
    import net.fxug.hokuriku.chocolat.service.VoteManager;
    import net.fxug.hokuriku.chocolat.utils.FilterUtil;
    import net.fxug.hokuriku.chocolat.utils.LoggingUtil;
    import net.fxug.hokuriku.chocolat.view.SpeakerSetting;

    /**
     * スピーカー設定画面のヘルパークラス
     *
     * @author shoito, hikaruworld
     */
    public class SpeakerSettingHelper implements IMXMLObject
    {
		private static var logger:ILogger = LoggingUtil.getLogger(SpeakerSettingHelper);
        private var view:SpeakerSetting;

        /** DB管理マネージャ */
        private var dbManager:DatabaseManager;

        public function initialized(document:Object, id:String):void
        {
            this.view = document as SpeakerSetting;
            this.view.addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
            this.view.filters = [FilterUtil.getDropShadowFilter()];
        }

        /**
         * セッション時間をミリ秒で返す
         */
        private function getSessionBasetime():uint
        {
            var baseHours:int = this.view.hours.value;
            var baseMinute:int = this.view.minutes.value;
            var baseSecond:int = this.view.seconds.value;

            return (baseHours * 3600 + baseMinute * 60 + baseSecond) * 1000;
        }

        private function creationCompleteHandler(event:FlexEvent):void
        {
			logger.debug("creationCompleteHandler ....");
            // 画面生成時にDBへ接続
            this.dbManager = DatabaseManager.getInstance();
            this.dbManager.addEventListener(SQLEvent.OPEN, databaseOpenHandler);
            this.dbManager.addEventListener(SQLErrorEvent.ERROR, dbManager_sqlErrorEventHandler);
            this.dbManager.connect();
        }

        /**
         * DB接続に成功した場合に実行されるイベントハンドラ
         * このハンドラが初期化処理にあたる。
         */
        private function databaseOpenHandler(sqlEvent:SQLEvent):void
        {
            logger.debug("database opend ....");

            this.view.start.addEventListener(MouseEvent.CLICK, start_clickHandler);
            this.view.back.addEventListener(MouseEvent.CLICK, back_clickHandler);

            // ネットワークインターフェイスを解決
            // TODO この画面が最初に表示された段階で解決されたIPアドレスのみ表示される。必要に応じて画面表示時に再度検索するように要調整
            var networkInterfaceManager:NetworkInterfaceManager = new NetworkInterfaceManager();

            try
            {
                var networkDataList:Array = networkInterfaceManager.getNetworkInterfaceDataList();
            }
            catch (e:NetworkInterfaceError)
            {
                // TODO 「ネットワーク設定でIPV6を無効にすれば正常に動作することがあります」等の表示を出して終了
                //TODO エラーに関してはユーザ対応に応じてある程度階層化したいところ。
                throw e;
            }

            //TODO ネットワークインターフェイスが空の場合のViewへの通知。
            //FIXME 暫定的にLabelを設定。
            var viewNetworkArray:Array = [];
            var index:int = networkDataList.length;
            for (var i:int = 0; i < index; i++)
            {
                var tmp:NetworkInterfaceData = networkDataList[i];
                viewNetworkArray.push({"label": tmp.name + "::" + tmp.address, "data": tmp})
            }
            this.view.speakerAddress.dataProvider = new ArrayCollection(viewNetworkArray);
        }

        /**
         * DB処理中に発生したイベントハンドラ
         */
        private function dbManager_sqlErrorEventHandler(sqlErrorEvent:SQLErrorEvent):void
        {
			logger.debug("sql error Event handler...text::{0}", sqlErrorEvent.text);
            //TODO エラー処理 -> DB接続できなかった場合はアプリケーションを終了するか、再度接続するか...
        }

        private function start_clickHandler(event:MouseEvent):void
        {
            // 開始前にDBにセッション情報を登録する。
            var sessionDao:SessionDao = new SessionDao();
            sessionDao.sessionTag = this.view.sessionTag.text;
            sessionDao.startDatetime = new Date();
            sessionDao.title = this.view.hashTag.text;
            dbManager.addEventListener(SQLVoteEvent.INSERT_SESSION_EVENT, dbManager_insertSessionEventHandler);
            // 同じ秒数内に同時に起動した場合にDBに同じkeyが書き込まれる可能性があるけど...
            dbManager.addEventListener(SQLErrorEvent.ERROR, dbManager_sqlErrorEventHandler);
            dbManager.insertSession(sessionDao);
        }

        /**
         * DBへセッション情報登録が正常に完了した場合のイベントハンドラ
         */
        private function dbManager_insertSessionEventHandler(sqlVoteEvent:SQLVoteEvent):void
        {
			logger.debug("dbManager_insertSessionEventHandler");
            this.dbManager.removeEventListener(SQLVoteEvent.INSERT_SESSION_EVENT, dbManager_insertSessionEventHandler);

            //DB登録完了後に、投票管理クラスを起動
            var vote:VoteManager = VoteManager.getInstance();
            var interfaceData:NetworkInterfaceData = this.view.speakerAddress.selectedItem.data as NetworkInterfaceData;
            // Twitterのインターフィエスに関してはユーザの入力内容(ハッシュタグ)を基準に判定
            var interfaces:Vector.<IVoteWatcher> = Vector.<IVoteWatcher>([]);
            if (this.view.hashTag.length != 0)
            {
                var twitterWatcher:TwitterSearchVoteWatcher = new TwitterSearchVoteWatcher(this.view.hashTag.text, this.getSessionBasetime(), this.view.sessionTag.text);
                interfaces.push(twitterWatcher);
            }
            var serverWatcher:SocketServer = new SocketServer(interfaceData);
            interfaces.push(serverWatcher);
            vote.targetInterfaces = interfaces;
            vote.addEventListener(VoteStatusEvent.READY_EVENT, voteManager_readyEventHandler);
            var sessionId:int = sqlVoteEvent.data as int;
            ApplicationDataModel.getInstance().sessionId = sessionId;
            vote.ready(sessionId);

        }

        private function voteManager_readyEventHandler(voteStatusEvent:VoteStatusEvent):void
        {
            VoteManager.getInstance().removeEventListener(VoteStatusEvent.READY_EVENT, voteManager_readyEventHandler);

            var period:int = getTimeMillis(this.view.hours.value, this.view.minutes.value, this.view.seconds.value);
            var bonus:int = getTimeMillis(0, this.view.bonusMinutes.value, this.view.bonusSeconds.value);

            var timerModel:SessionTimer = SessionTimer.getInstance();
            timerModel.period = period;
            timerModel.bonus = bonus;
            timerModel.start();

            var timerEvent:SessionTimerEvent = new SessionTimerEvent(SessionTimerEvent.START);
            this.view.dispatchEvent(timerEvent);

        }

        private function getTimeMillis(hours:int, minutes:int, seconds:int):int
        {
            var time:int = ((hours * 60 + minutes) * 60 + seconds) * 1000;
            return time;
        }

        private function back_clickHandler(event:Event):void
        {
            this.view.dispatchEvent(new ViewChangeEvent(ViewChangeEvent.BACK));
        }
    }
}